package com.example.examsystem.service;

import com.example.examsystem.dto.PageResponse;
import com.example.examsystem.dto.RoleDto;
import com.example.examsystem.exception.BusinessException;
import com.example.examsystem.model.Role;
import com.example.examsystem.model.RolePermission;
import com.example.examsystem.repository.RolePermissionRepository;
import com.example.examsystem.repository.RoleRepository;
import com.example.examsystem.repository.UserRoleRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色管理服务类
 * 提供角色的业务逻辑处理，包括角色增删改查、权限分配等
 * 
 * @author system
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleService {

    private final RoleRepository roleRepository;
    private final RolePermissionRepository rolePermissionRepository;
    private final UserRoleRepository userRoleRepository;

    /**
     * 分页查询角色列表
     * 支持按角色名称、描述进行筛选
     * 
     * @param page 页码（从0开始）
     * @param size 每页大小
     * @param name 角色名称（模糊查询，可为空）
     * @param description 角色描述（模糊查询，可为空）
     * @return 分页角色数据
     */
    public PageResponse<RoleDto> getRoles(int page, int size, String name, String description) {
        log.debug("查询角色列表 - 页码: {}, 大小: {}, 筛选条件: 名称={}, 描述={}", 
                page, size, name, description);
        
        // 创建分页对象，按创建时间倒序排列
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<Role> rolePage = roleRepository.findByQuery(name, description, pageable);
        
        // 转换为DTO
        List<RoleDto> content = rolePage.getContent().stream()
            .map(this::convertToDtoList)
            .collect(Collectors.toList());
        
        log.debug("查询到角色数量: {}", content.size());
        
        return new PageResponse<>(
            content,
            rolePage.getNumber(),
            rolePage.getSize(),
            rolePage.getTotalElements(),
            rolePage.getTotalPages()
        );
    }

    /**
     * 获取所有角色（不分页）
     * 按创建时间排序
     * 
     * @return 所有角色列表
     */
    public List<RoleDto> getAllRoles() {
        log.debug("获取所有角色列表");
        List<Role> roles = roleRepository.findAllByOrderByCreatedAt();
        return roles.stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
    }

    /**
     * 根据ID获取角色详情
     * 
     * @param id 角色ID
     * @return 角色详情
     * @throws BusinessException 角色不存在时抛出
     */
    public RoleDto getRoleById(Long id) {
        log.debug("获取角色详情 - ID: {}", id);
        Role role = roleRepository.findById(id)
            .orElseThrow(() -> new BusinessException("角色不存在"));
        return convertToDto(role);
    }

    /**
     * 创建新角色
     * 会检查角色名称的唯一性
     * 
     * @param roleDto 角色信息
     * @return 创建的角色信息
     * @throws BusinessException 角色名称已存在时抛出
     */
    @Transactional
    public RoleDto createRole(RoleDto roleDto) {
        log.info("开始创建角色 - 名称: {}", roleDto.getName());
        
        // 检查角色名称是否已存在
        if (roleRepository.existsByName(roleDto.getName())) {
            throw new BusinessException("角色名称已存在");
        }
        
        // 创建角色实体
        Role role = new Role();
        role.setName(roleDto.getName());
        role.setDescription(roleDto.getDescription());
        
        Role savedRole = roleRepository.save(role);
        log.info("角色创建成功 - ID: {}, 名称: {}", savedRole.getId(), savedRole.getName());
        
        // 分配权限（如果提供了权限ID）
        if (roleDto.getPermissionIds() != null && roleDto.getPermissionIds().length > 0) {
            log.info("为新角色分配权限 - 角色ID: {}, 权限数量: {}", savedRole.getId(), roleDto.getPermissionIds().length);
            assignPermissions(savedRole.getId(), roleDto.getPermissionIds());
        }
        
        return convertToDto(savedRole);
    }

    /**
     * 更新角色信息
     * 会检查角色名称的唯一性（排除当前角色）
     * 
     * @param id 角色ID
     * @param roleDto 更新的角色信息
     * @return 更新后的角色信息
     * @throws BusinessException 角色不存在或角色名称重复时抛出
     */
    @Transactional
    public RoleDto updateRole(Long id, RoleDto roleDto) {
        log.info("开始更新角色 - ID: {}", id);
        
        Role role = roleRepository.findById(id)
            .orElseThrow(() -> new BusinessException("角色不存在"));
        
        // 检查角色名称是否重复（排除当前角色）
        if (!role.getName().equals(roleDto.getName()) && 
            roleRepository.existsByName(roleDto.getName())) {
            throw new BusinessException("角色名称已存在");
        }
        
        // 更新角色信息
        role.setName(roleDto.getName());
        role.setDescription(roleDto.getDescription());
        
        Role savedRole = roleRepository.save(role);
        log.info("角色信息更新成功 - ID: {}", id);
        
        // 更新权限分配
        if (roleDto.getPermissionIds() != null) {
            log.info("更新角色权限 - 角色ID: {}, 权限数量: {}", id, roleDto.getPermissionIds().length);
            assignPermissions(savedRole.getId(), roleDto.getPermissionIds());
        }
        
        return convertToDto(savedRole);
    }

    /**
     * 删除角色
     * 会检查是否有用户正在使用该角色，如果有则不允许删除
     * 同时会删除角色的权限关联关系
     * 
     * @param id 角色ID
     * @throws BusinessException 角色不存在或正在被使用时抛出
     */
    @Transactional
    public void deleteRole(Long id) {
        log.info("开始删除角色 - ID: {}", id);
        
        Role role = roleRepository.findById(id)
            .orElseThrow(() -> new BusinessException("角色不存在"));
        
        // 检查是否有用户使用该角色
        List<Long> userIds = userRoleRepository.findUserIdsByRoleId(id);
        if (!userIds.isEmpty()) {
            log.warn("角色正在被使用，无法删除 - 角色ID: {}, 使用用户数量: {}", id, userIds.size());
            throw new BusinessException("该角色正在被用户使用，无法删除");
        }
        
        // 删除角色权限关联
        log.debug("删除角色权限关联 - 角色ID: {}", id);
        rolePermissionRepository.deleteByRoleId(id);
        
        // 删除角色
        roleRepository.delete(role);
        log.info("角色删除成功 - ID: {}, 名称: {}", id, role.getName());
    }

    /**
     * 为角色分配权限
     * 会先删除角色现有的所有权限，然后分配新的权限
     * 
     * @param roleId 角色ID
     * @param permissionIds 权限ID数组（可为空或空数组）
     */
    @Transactional
    public void assignPermissions(Long roleId, Long[] permissionIds) {
        log.info("为角色分配权限 - 角色ID: {}, 权限数量: {}", roleId, permissionIds != null ? permissionIds.length : 0);
        
        // 删除角色现有的所有权限
        rolePermissionRepository.deleteByRoleId(roleId);
        log.debug("已删除角色现有权限 - 角色ID: {}", roleId);
        
        // 分配新权限
        if (permissionIds != null && permissionIds.length > 0) {
            List<RolePermission> rolePermissions = Arrays.stream(permissionIds)
                .map(permissionId -> {
                    RolePermission rolePermission = new RolePermission();
                    rolePermission.setRoleId(roleId);
                    rolePermission.setPermissionId(permissionId);
                    return rolePermission;
                })
                .collect(Collectors.toList());
            
            rolePermissionRepository.saveAll(rolePermissions);
            log.info("权限分配成功 - 角色ID: {}, 分配权限数量: {}", roleId, permissionIds.length);
        } else {
            log.info("未分配任何权限 - 角色ID: {}", roleId);
        }
    }

    /**
     * 获取角色的权限列表
     * 
     * @param roleId 角色ID
     * @return 权限ID列表
     */
    public List<Long> getRolePermissions(Long roleId) {
        log.debug("获取角色权限列表 - 角色ID: {}", roleId);
        return rolePermissionRepository.findPermissionIdsByRoleId(roleId);
    }

    /**
     * 将Role实体转换为RoleDto
     * @param role 角色实体
     * @return 角色DTO
     */
    private RoleDto convertToDtoList(Role role) {
        RoleDto dto = new RoleDto();
        dto.setId(role.getId());
        dto.setName(role.getName());
        dto.setDisplayName(role.getDisplayName());
        dto.setDescription(role.getDescription());
        dto.setCreatedAt(role.getCreatedAt());
        dto.setUpdatedAt(role.getUpdatedAt());
        return dto;
    }

    /**
     * 将Role实体转换为RoleDto
     * 包含角色基本信息和关联的权限信息
     *
     * @param role 角色实体
     * @return 角色DTO
     */
    private RoleDto convertToDto(Role role) {
        RoleDto dto = new RoleDto();
        dto.setId(role.getId());
        dto.setName(role.getName());
        dto.setDisplayName(role.getDisplayName());
        dto.setDescription(role.getDescription());
        dto.setCreatedAt(role.getCreatedAt());
        dto.setUpdatedAt(role.getUpdatedAt());

        // 获取角色权限信息
        List<Long> permissionIds = rolePermissionRepository.findPermissionIdsByRoleId(role.getId());
        dto.setPermissionIds(permissionIds.toArray(new Long[0]));

        return dto;
    }
}
